#ifndef TRANSFORMATIONHOMOGENE_HPP
#define TRANSFORMATIONHOMOGENE_HPP

#include "MatriceSO3.hpp"
#include "Vecteur.hpp"

#include <functional>
#include <vector>

/** @brief Classe implémentant une transformation de l'espace en coordonnées
 * homogènes.
 *
 * Cette classe implémente une transformation de l'espace en coordonnées
 * homogènes, càd que le calcul est effectué avec une matrice 4x4 et un vecteur
 * de dimension 4. Une multiplication par une telle matrice peut représenter
 * une rotation et une translation en une seule étape.
 *
 * @author Johan "Solo" Luisier
 * @date 07 Juin 2014
 *
 * @class TransformationHomogene "TransformationHomogene.hpp"
 * "Algebre/TransformationHomogene.hpp"
 */
class TransformationHomogene : public MatriceBase
{
public:
    /** @brief Constructeur qui promeut une rotation en une transformation
     * homogène.
     *
     * Ce constructeur initialise la matrice 4x4 et copie la rotation dans le
     * bloc approprié.
     *
     * @param[in] rotation matrice de rotation 3x3.
     */
    TransformationHomogene( const MatriceSO3& rotation );
    /** @brief Constructeur qui promeut une translation en une transformation
     * homogène.
     *
     * Ce constructeur initialise la matrice 4x4 et copie la translation dans
     * le bloc approprié.
     *
     * @param[in] translation vecteur de translation.
     */
    TransformationHomogene( const Vecteur& translation );
    /** @brief Constructuer qui promeut une homothétie en une transformation
     * homogène.
     *
     * Ce constructeur initialise la matrice 4x4 et recopie le facteur
     * d'homothétie sur les 3 premiers éléments diagonaux.
     *
     * @param[in] homothetie facteur d'homothétie.
     */
    TransformationHomogene( const double& homothetie = 1. );
    /** @brief Constructeur de copie.
     *
     * Ce constructeur permet de dupliquer une instance.
     *
     * @param[in] autre instance de TransformationHomogene à dupliquer.
     */
    TransformationHomogene( const TransformationHomogene& autre );
    /** @brief Destructeur, @c virtual pour assurer une séquence de destruction
     * correcte.
     *
     * La désallocation de mémoire est déléguée à la classe mère.
     */
    virtual ~TransformationHomogene();

    /** @brief Opérateur d'affectation.
     *
     * Cet opérateur permet de copier une instance dans une l'instance courante.
     *
     * @param[in] autre instance à copier dans l'instance courante.
     *
     * @return une référence sur l'instance courante.
     */
    TransformationHomogene& operator=( const TransformationHomogene& autre );

    /** @brief Opérateur de composision de transformations.
     *
     * Cet opérateur permet de composer deux instances de
     * TransformationHomogene, en modifiant l'instance courante. La composition
     * s'obtient en multipliant @e à @e droite l'instance courante par la
     * deuxieme instance.
     *
     * @param[in] autre instance avec laquelle composer l'instance courante.
     *
     * @return une référence sur l'instance courante.
     */
    TransformationHomogene& operator*=( const TransformationHomogene& autre );

    /** @brief Opérateur de composision de transformations.
     *
     * Cet opérateur permet de composer deux instances de
     * TransformationHomogene en une nouvelle instance. La composition
     * s'obtient en multipliant @e à @e droite l'instance courante par la
     * deuxieme instance.
     *
     * Appelle l'opérateur *= sur une instance temporaire.
     *
     * @param[in] autre instance avec laquelle composer l'instance courante.
     *
     * @return une nouvelle instance, résultant de la composition.
     */
    TransformationHomogene operator*( const TransformationHomogene& autre );

    /** @brief Accesseur pour les éléments de la matrice.
     *
     * Cette méthode permet d'accéder à un élément de la matrice.
     *
     * @param[in] i indice de la ligne désirée,
     * @param[in] j indice de la colonne désirée.
     *
     * @return une référence constante sur la valeur dédirée.
     */
    const double& at( const unsigned& i, const unsigned& j ) const;

    /** @brief Méthode d'inversion de la matrice.
     *
     * Cette méthode permet d'obtenir la transformation inverse. Une
     * décomposition LU est utilisée pour obtenir cette nouvelle transformation.
     *
     * @param[out] inv
     *
     * @retval true si l'inverse existe,
     * @retval false si l'inverse n'existe pas.
     */
    bool inverse( TransformationHomogene& inv ) const;
private:
    TransformationHomogene& operator=( const MatriceBase& mat );
};

#endif // TRANSFORMATIONHOMOGENE_HPP
